package com.faxsun.web.controller.user;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import mblog.core.pojos.Tag;
import mblog.core.pojos.User;
import mblog.web.controller.BaseController;
import mtons.modules.lang.Const;
import mtons.modules.pojos.Page;
import mtons.modules.pojos.UserContextHolder;
import mtons.modules.pojos.UserProfile;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.faxsun.core.persist.entity.FollowListPO;
import com.faxsun.core.persist.entity.UserPO;
import com.faxsun.core.service.FollowListService;
import com.faxsun.core.service.TagService;
import com.faxsun.core.service.UserService;
import com.faxsun.web.controller.FrontViewConstants;
import com.faxsun.web.pojos.FSUserProfile;
import com.faxsun.web.utils.VisiblePage;

@Controller
@RequestMapping("/users")
public class UserCenterController extends BaseController {

    @SuppressWarnings("unused")
	private static final Logger LOG = LoggerFactory.getLogger(UserCenterController.class);
    
    private static final int PAGINATION_SIZE = 8;
    
    private static final int PAGINATION_DFLT_VISIBLE_SIZE = 5;
    
    private static final int AVATAR_GROUP_MAX = 12;
    
    @Autowired
    protected FollowListService flService;

    @Autowired
    protected TagService tagService;

    @Autowired
    protected UserService userService;

    @RequestMapping(value = "/{userId}", method = RequestMethod.GET)
    public String getCenter(@PathVariable Long userId, ModelMap model, HttpServletRequest request) {

        if(!userValid(userId)){
           return FrontViewConstants.VIEW_404;
        }
        
        model.addAttribute("userId", userId);  

        UserProfile up = UserContextHolder.getUserProfile();
        String isUserFollowed = "false";        
        
        boolean authorized = this.authorized(userId);        
    	if(authorized){
            model.addAttribute("authorized", "true");
    	} else{
            //return "redirect:/";            
            model.addAttribute("authorized", "false");     

            if(up != null && up.getId() > 1){
               FollowListPO fl = flService.findFollow(userId, up.getId(), 0);//user
               if(fl != null && fl.getStatus() == 0){//followed
                  isUserFollowed = "true";
               }
            }           

            User u = userService.get(userId.longValue());
            up = new FSUserProfile(u.getId(), u.getUsername());
            up.setAvatar(u.getAvatar());
            up.setLastLogin(u.getLastLogin());
            up.setEmail(u.getEmail());
            up.setName(u.getName());
            ((FSUserProfile)up).setSignature(u.getSignature());
    	}
    	model.addAttribute("profile", up);
        model.addAttribute("isUserFollowed", isUserFollowed);

        int userFollowedCount = flService.countAllMyFollowers(userId, 0);
        model.addAttribute("userFollowedCount", userFollowedCount);
        
        //load followed products
        loadPage(userId, model, request, 1, 
                true, 1, "followed_count", "maxPage", "prevPage", "nextPage",
                "url", "/fp", "visiblePages", "products");     

        //load followed users
        loadPage(userId, model, request, 1, 
                 true, 0, "friendFollowed_count", "friendFollowed_maxPage", "friendFollowed_prevPage", "friendFollowed_nextPage",
                 "friendFollowed_url", "/followedUsers", "friendFollowed_visiblePages", "friendFolloweds");    

        //load followers
        loadPage(userId, model, request, 1, 
                 false, 0, "friendFollower_count", "friendFollower_maxPage", "friendFollower_prevPage", "friendFollower_nextPage",
                 "friendFollower_url", "/followers", "friendFollower_visiblePages", "friendFollowers");
        
        model.addAttribute("hintAvatar", up.getAvatar().contains("head")? "true" : "false");
        return FrontViewConstants.VIEW_USER_CENTER;
    }
    
    @RequestMapping(value = "/avatars", method = RequestMethod.POST)
    public String fetchAvatars(ModelMap model, HttpServletRequest request) {  
        String group = request.getParameter("group");
        if(group != null && group.length() > 0){
           model.addAttribute("avatars", getAvatars(group, request)); 
        }else{
           model.addAttribute("avatars", "venus");  
        }
        return FrontViewConstants.VIEW_USER_AVATAR_SLIDER;
    }

    @SuppressWarnings("rawtypes")
	@RequestMapping(value = "/{userId}/avatar", method = RequestMethod.POST)
    public ResponseEntity<?> updateAvatar(@PathVariable Long userId, ModelMap model, HttpServletRequest request) {
        if(!userValid(userId)){
            return new ResponseEntity(HttpStatus.NOT_FOUND);  
        }
        
        boolean authorized = this.authorized(userId);
        if(!authorized){
           return new ResponseEntity(HttpStatus.UNAUTHORIZED);
        }
        
        String group = request.getParameter("group");
        String avatar = request.getParameter("avatar");
        if((avatar != null && avatar.length() > 0) && (group != null && group.length() > 0)){
           String avatarSrc = "/src/img/avatar/" + group + "/" + avatar + ".png";
           UserProfile up = userService.updateAvatar(userId, avatarSrc);
           updateProfile(up);           
           return new ResponseEntity(HttpStatus.OK);            
        }else{
           return new ResponseEntity(HttpStatus.BAD_REQUEST);
        }
    }

    @SuppressWarnings("rawtypes")
	@RequestMapping(value = "/{userId}/name", method = RequestMethod.POST)
    public ResponseEntity<?> updateName(@PathVariable Long userId, ModelMap model, HttpServletRequest request) {
        if(!userValid(userId)){
            return new ResponseEntity(HttpStatus.NOT_FOUND);  
        }
        
        boolean authorized = this.authorized(userId);
        if(!authorized){
           return new ResponseEntity(HttpStatus.UNAUTHORIZED);
        }
        
        String name = request.getParameter("name");
        if(name != null && name.length() > 0){
           UserProfile up = userService.updateName(userId, name);
           updateProfile(up);
           return new ResponseEntity(HttpStatus.OK);            
        }else{
           return new ResponseEntity(HttpStatus.BAD_REQUEST);
        }
    }

    @SuppressWarnings("rawtypes")
    @RequestMapping(value = "/{userId}/signature", method = RequestMethod.POST)
    public ResponseEntity<?> updateSignature(@PathVariable Long userId, ModelMap model, HttpServletRequest request) {
        if(!userValid(userId)){
            return new ResponseEntity(HttpStatus.NOT_FOUND);  
        }
        
        boolean authorized = this.authorized(userId);
        if(!authorized){
           return new ResponseEntity(HttpStatus.UNAUTHORIZED);
        }
        
        String signature = request.getParameter("signature");
        if(signature != null && signature.length() > 0){
           UserProfile up = userService.updateSignature(userId, signature);
           updateProfile(up);
           return new ResponseEntity(HttpStatus.OK);            
        }else{
           return new ResponseEntity(HttpStatus.BAD_REQUEST);
        }
    }
    
    @RequestMapping(value = "/{userId}/fp", method = RequestMethod.POST)
    public String getFollowedProducts(@PathVariable Long userId, ModelMap model, HttpServletRequest request) {

        if(!userValid(userId)){
           return FrontViewConstants.VIEW_404;
        }

        String targetPage = request.getParameter("page");
        
        loadPage(userId, model, request, Integer.parseInt(targetPage), 
                 true, 1, "followed_count", "maxPage", "prevPage", "nextPage",
                 "url", "/fp", "visiblePages", "products");
        
        return FrontViewConstants.VIEW_USER_FOLLOWED_PRODUCTS;
    }
    
    @RequestMapping(value = "/{userId}/followedUsers", method = RequestMethod.POST)
    public String getFollowedUsers(@PathVariable Long userId, ModelMap model, HttpServletRequest request) {

        if(!userValid(userId)){
           return FrontViewConstants.VIEW_404;
        }

        String targetPage = request.getParameter("page");
        
        loadPage(userId, model, request, Integer.parseInt(targetPage), 
                 true, 0, "friendFollowed_count", "friendFollowed_maxPage", "friendFollowed_prevPage", "friendFollowed_nextPage",
                 "friendFollowed_url", "/followedUsers", "friendFollowed_visiblePages", "friendFolloweds");
        
        return FrontViewConstants.VIEW_USER_FOLLOWED_PRODUCTS;
    }
    
    @RequestMapping(value = "/{userId}/followers", method = RequestMethod.POST)
    public String getFollowers(@PathVariable Long userId, ModelMap model, HttpServletRequest request) {

        if(!userValid(userId)){
           return FrontViewConstants.VIEW_404;
        }

        String targetPage = request.getParameter("page");
        
        loadPage(userId, model, request, Integer.parseInt(targetPage), 
                 false, 0, "friendFollower_count", "friendFollower_maxPage", "friendFollower_prevPage", "friendFollower_nextPage",
                 "friendFollower_url", "/followers", "friendFollower_visiblePages", "friendFollowers");
        
        return FrontViewConstants.VIEW_USER_FOLLOWERS;
    }
    
    /**
     * This is to load items for followed products/followed users/followers for a given user.
     * check "view/partials/productpage" or "view/authentication/partials/friend" for an example
     * @param userId the user id to fetch info
     * @param model 
     * @param request
     * @param targetPageId target list page id
     * @param followed true if load followed product or followed user
     * @param followType 0-user,1-product
     * @param countAttr item count attribute name in thymealeaf html template
     * @param maxPageAttr max page id attribute name in thymealeaf html template
     * @param prevPageAttr prev page id attribute name in thymealeaf html template
     * @param nextPageAttr next page id attribute name in thymealeaf html template
     * @param urlAttr paging url attribute name in thymealeaf html template
     * @param urlPath item detail url path attribute name in thymealeaf html template
     * @param visiblePagesAttr visible page attribute name in thymealeaf html template
     * @param itemsAttr items attribute name in thymealeaf html template
     */
    private void loadPage(Long userId, ModelMap model, HttpServletRequest request, int targetPageId, 
            boolean followed, int followType, String countAttr, String maxPageAttr, String prevPageAttr, String nextPageAttr, 
            String urlAttr, String urlPath, String visiblePagesAttr, String itemsAttr){
        
        User displayedUser = userService.get(userId); 
        model.addAttribute("userDisplayedName", displayedUser.getName());
        
        int count = 0;        
        switch(followType){
          default:
          case 0:{//user
            if(followed){
               count = flService.countAllMyFollows(userId, 0);                  
            }else{
               count = flService.countAllMyFollowers(userId, 0);                  
            }
            break;
          }
          case 1:{//product
            count = flService.countAllMyFollows(userId, 1);
            break;
          }
          case 2://evaluation
            break;
          case 3://news
            break;
        }
        model.addAttribute(countAttr, count);
        
        int curPageId = targetPageId;
        
        if(count > 0){   
            // add max page
            int maxPageId = (count / PAGINATION_SIZE) + (count % PAGINATION_SIZE == 0? 0 : 1);              
            if(curPageId > maxPageId){
               curPageId = maxPageId;    
            }            
            model.addAttribute(maxPageAttr, maxPageId);
            //model.addAttribute("curPage", curPageId);
            model.addAttribute(prevPageAttr, curPageId - 1 < 1? 1 : curPageId - 1);
            model.addAttribute(nextPageAttr, curPageId + 1 > maxPageId? maxPageId : curPageId + 1);
            
            // add post url
            String contextPath = request.getContextPath();
            String url = contextPath + "/users/" + userId + urlPath;
            model.addAttribute(urlAttr, url); 
            
            // add visible page for pagination
            List<VisiblePage> visiblePages = new ArrayList<VisiblePage>(PAGINATION_DFLT_VISIBLE_SIZE);
            int startPageId = curPageId - 2 < 1 ? 1 : curPageId - 2;
            int endPageId = curPageId + 2 > maxPageId ? maxPageId : curPageId + 2;            
            for(int i = startPageId;i <= endPageId;i++){
                VisiblePage vp = new VisiblePage();
                vp.setId(i);
                if(i == curPageId){
                   vp.setCurPage(true); 
                }
                visiblePages.add(vp);
            }
            model.addAttribute(visiblePagesAttr, visiblePages); 
            
            // add products for current page
            Page page = wrapPage(curPageId);
            page.setMaxResults(PAGINATION_SIZE);
            
            List<FollowListPO> allItems = Collections.emptyList();
            switch(followType){
              default:
              case 0:{//user
                if(followed){
                   allItems = flService.findAllMyFollows(page, userId, 0);                  
                }else{
                   allItems = flService.findAllMyFollowers(page, userId, 0);                  
                }
                break;
              }
              case 1:{//product
                allItems = flService.findAllMyFollows(page, userId, 1);
                break;
              }
            }            
            
            List<FollowedItem> items = new ArrayList<FollowedItem>(allItems.size());
            for(FollowListPO fl : allItems){
                FollowedItem fp = new FollowedItem();
                
                switch(followType){
                  default:
                  case 0:{//user
                    if(followed){
                       User u = userService.get(fl.getUid()); 
                       fp.setImageUrl(u.getAvatar());
                       String fpUrl = contextPath + "/users/" + u.getId();
                       fp.setUrl(fpUrl);
                    }else{
                       long uoId = fl.getFollower_id(); 
                       UserPO upo = userService.findUserPOBy(uoId);
                       fp.setImageUrl(upo.getAvatar());
                       String fpUrl = contextPath + "/users/" + uoId;
                       fp.setUrl(fpUrl);                  
                    }
                    break;
                  }
                  case 1:{//product                     
                    Tag product = tagService.getById(fl.getUid());
                    fp.setImageUrl(product.getProduct().getDefaultImageUrl());
                    String fpUrl = contextPath + "/product/view/" + product.getId();
                    fp.setUrl(fpUrl);
                    break;
                  }
                }
                
                items.add(fp);
            }
            model.addAttribute(itemsAttr, items); 
        }
    }
    
    private void updateProfile(UserProfile up){        
        UserProfile oldUp = (UserProfile) session.getAttribute(Const.KEY_LOGIN);
        up.setLastLogin(oldUp.getLastLogin());           
        session.setAttribute(Const.KEY_LOGIN, up);           
        UserContextHolder.setUserProfile(up);        
    }
    
    private List<String> getAvatars(String group, HttpServletRequest request){
        List<String> ret = new ArrayList<String>();
        String ctx = request.getContextPath();
        if(group.equalsIgnoreCase("venus")){
           for(int i = 1;i <= AVATAR_GROUP_MAX; i++){
               ret.add(ctx + "/src/img/avatar/venus/" + i + ".png");
           }
        }else if(group.equalsIgnoreCase("mars")){
           for(int i = 1;i <= AVATAR_GROUP_MAX; i++){
               ret.add(ctx + "/src/img/avatar/mars/" + i + ".png");
           }
        }else if(group.equalsIgnoreCase("hallowean")){
           for(int i = 1;i <= AVATAR_GROUP_MAX; i++){
               ret.add(ctx + "/src/img/avatar/hallowean/" + i + ".png");
           }
        }else if(group.equalsIgnoreCase("social")){
           for(int i = 1;i <= AVATAR_GROUP_MAX; i++){
               ret.add(ctx + "/src/img/avatar/social/" + i + ".png");
           }
        }else if(group.equalsIgnoreCase("summer")){
           for(int i = 1;i <= AVATAR_GROUP_MAX; i++){
               ret.add(ctx + "/src/img/avatar/summer/" + i + ".png");
           }
        }else if(group.equalsIgnoreCase("animal")){
           for(int i = 1;i <= AVATAR_GROUP_MAX; i++){
               ret.add(ctx + "/src/img/avatar/animal/" + i + ".png");
           }
        }else if (group.equalsIgnoreCase("zodiac")) {
            for (int i = 1; i <= AVATAR_GROUP_MAX; i++) {
                ret.add(ctx + "/src/img/avatar/zodiac/" + i + ".png");
            }
        }else if(group.equalsIgnoreCase("romons")){
            for(int i = 1;i <= AVATAR_GROUP_MAX; i++){
                ret.add(ctx + "/src/img/avatar/romons/" + i + ".png");
            }
        }         
        return ret;
    }
    
    /**
     * check if current user has required permission for action like update avatar/name
     * @param userId the user id upon which action is taken
     * @return true if authorization ok otherwise false
     */
    private boolean authorized(Long userId){
        UserProfile up = UserContextHolder.getUserProfile();
        if(up == null || up.getId() < 1 || up.getId() != userId.longValue()){
            return false;
        } else{
            return true;
        }
    }
    
    private boolean userValid(Long userId){
        User u = userService.get(userId.longValue());
        if(u == null){
           return false;
        }else{
           return true;
        }
    }
    
    public class FollowedItem{
        private String url;
        private String imageUrl;
        
        public String getUrl() {
            return url;
        }
        public void setUrl(String url) {
            this.url = url;
        }
        public String getImageUrl() {
            return imageUrl;
        }
        public void setImageUrl(String imageUrl) {
            this.imageUrl = imageUrl;
        }        
    }
    
    
    
}
